package main

import (
	"fmt"
	"reflect"
)

func main() {

	//1.对基本数据类型进行反射
	//var num int64 = 19
	//调用方法测试放射
	//testReflectNum(num)
	// 修改反射的值
	//testReflectNum2(&num)
	// 变成修改后的值
	//fmt.Printf("num==>{%d}", num)

	//2.对结构体
	stu := Student{
		Id:     1100,
		Name:   "文轩",
		Score:  "98",
		Remark: "这个学生很乖",
	}
	// 测试结构体
	//testReflectStruct(stu)

	//改变结构体内字段的值（结构体本身就是引用类型不用&）
	//testReflectStruct2(stu)
	//fmt.Printf("stu=>{%s}", stu)

	testReflectStruct3(&stu)
	fmt.Printf("stu=>{%s}", stu)
}

func testReflectStruct(clazz interface{}) {
	// 通过反射获取type类型和值value
	reType := reflect.TypeOf(clazz)
	reValue := reflect.ValueOf(clazz)

	fmt.Printf("reType==>{%s}\n", reType)
	fmt.Printf("reValue==>{%s}\n", reValue)

	//类型是结构体struct
	fmt.Printf("reType 类型==>{%s}\n", reType.Kind())
	fmt.Printf("reValue 类型==>{%s}\n", reValue.Kind())

	realValue := reValue.Interface()

	assertStu, flag := realValue.(Student)
	if flag {
		fmt.Printf("assertValue==>{%v %v %v %v}\n", assertStu.Id, assertStu.Name, assertStu.Score, assertStu.Remark)
		fmt.Printf("类型是==>{%T\n", assertStu)
	}
}

func testReflectStruct2(clazz interface{}) {
	refValue := reflect.ValueOf(clazz)
	fmt.Printf("%s", refValue)

	numField := refValue.NumField()
	fmt.Println("numField==>", numField)

	for i := 0; i < numField; i++ {
		fmt.Printf("第%d个，值为%s", i, refValue.Field(i))
	}

	numMethod := refValue.NumMethod()
	fmt.Println("numMethod==>", numMethod)

	refValue.Method(0).Call(nil)
	// 参数是切片，我们构建一个切片
	var params []reflect.Value
	params = append(params, reflect.ValueOf(18))
	params = append(params, reflect.ValueOf(19))
	callResult := refValue.Method(1).Call(params)
	fmt.Printf("callResult==>{%d}\n", callResult[0])

	// 没有传入地址，不能修改原值
	var params2 []reflect.Value
	params2 = append(params2, reflect.ValueOf(120))
	params2 = append(params2, reflect.ValueOf("晨风"))
	params2 = append(params2, reflect.ValueOf("25"))
	params2 = append(params2, reflect.ValueOf("既然这样，那我就多说两句，你看这样行吗"))
	refValue.Method(2).Call(params2)
}

func testReflectStruct3(clazz interface{}) {
	refValue := reflect.ValueOf(clazz)
	fmt.Printf("%s\n", refValue)

	field := refValue.Elem().NumField()
	fmt.Printf("field==>{%d}\n", field)
	refValue.Elem().Field(0).SetInt(120)
	refValue.Elem().Field(1).SetString("蓝莲")
	refValue.Elem().Field(2).SetString("26")
	refValue.Elem().Field(3).SetString("既然这样，那我就多说两句，你看这样行吗")
}

func testReflectNum(clazz interface{}) {

	// 通过反射获取type类型和值value
	reType := reflect.TypeOf(clazz)
	reValue := reflect.ValueOf(clazz)

	fmt.Printf("reType==>{%s}\n", reType)
	fmt.Printf("reValue==>{%s}\n", reValue)

	fmt.Printf("reType 类型==>{%T}\n", reType)
	fmt.Printf("reValue 类型==>{%T}\n", reValue)

	// 转成int整型
	sourceValue := reValue.Int()
	fmt.Printf("sourceValue==>{%d}\n", sourceValue)

	realValue := reValue.Interface()

	//assertValue := realValue.(int16)
	assertValue := realValue.(int64)

	fmt.Printf("assertValue==>{%d}\n", assertValue)

}

func testReflectNum2(clazz interface{}) {
	refValue := reflect.ValueOf(clazz)
	refValue.Elem().SetInt(81)
}

type Student struct {
	Id     int
	Name   string
	Score  string
	Remark string
}

// APrint Print 给结构体绑定函数
func (stu Student) APrint() {
	fmt.Printf("调用了打印方法")
	fmt.Printf("学生的姓名是%v", stu.Name)
}

func (stu Student) BGetSum(n1, n2 int) int {
	fmt.Println("调用了BGetSum")
	return n1 + n2
}

func (stu Student) CSet(id int, name, score, remark string) {
	fmt.Printf("改变了stu的字段值")
	stu.Id = id
	stu.Name = name
	stu.Score = score
	stu.Remark = remark
}
